#include "RleManager.h"

RleManager::RleManager(FILE *file, Header &header) : file(file)
{
}

RleManager::~RleManager()
{
}

void RleManager::WriteHeader(Header &header)
{
	fwrite(&header, sizeof(Header), 1,  file);
}

void RleManager::ReadHeader()
{
	fread(&this->header, sizeof(Header),1, file);
}

Header &RleManager::GetHeader()
{
	return this->header;
}

bool RleManager::ReadBlock(int *buffer)
{
	return true;
}

bool RleManager::WriteBlockLuminance(int *block)
{
	this->RleEncodeLuminance(block);
	return true;
}

bool RleManager::WriteBlockCrominance(int *block)
{
	this->RleEncodeCrominance(block);
	return true;
}

static int countWrite = 0;
static int countRead = 0;

void RleManager::RleEncodeLuminance(int *block)
{
	int total = 0;
	short count = 0;
	short buffer[100];

	for (int i = 0; i < 64; ++i)
	{
		if (block[i] != 0)
		{
			if (count > 0)
			{
				short zero = 0;
				buffer[total] = zero;
				total += 1;
				buffer[total] = count;
				total += 1;
				count = 0;
			}
/*			if (block[i] > 127 && i != 0)
					block[i] = 127;
			if (block[i] < -127 && i != 0)
				block[i] = -127;*/
			buffer[total] = block[i];
			total += 1;
		}
		else
			count += 1;
	}
	if (count > 0)
	{
		short zero = 0;
		buffer[total] = zero;
		total += 1;
		buffer[total] = count;
		total += 1;
	}
	countWrite += fwrite(buffer, sizeof(short), total , file);
}

void DisplayTab3(int *tab)
{
	std::cout << std::endl;
	for (int i = 0; i < 64; ++i)
	{
		if (i % 8 == 0)
			std::cout << std::endl;
		std::cout << tab[i] << " ";
	}
	std::cout << std::endl;
}

void RleManager::RleEncodeCrominance(int *block)
{
	int total = 0;
	signed char buffer[100];
	uchar count = 0;

	countWrite += fwrite(&block[0], sizeof(short), 1, file);
	for (int i = 1; i < 64; ++i)
	{
		if (block[i] != 0)
		{
			if (count > 0)
			{
				uchar zero = 0;
				buffer[total] = zero;
				total += 1;
				buffer[total] = count;
				total += 1;
				count = 0;
			}
			if (block[i] > 127)
			{
				DisplayTab3(block);
				block[i] = 127;
				int a = 0;
			}
			buffer[total] = block[i];
			total += 1;
		}
		else
			count += 1;
	}
	if (count > 0)
	{
		uchar zero = 0;
		buffer[total] = zero;
    	total += 1;
		buffer[total] = count;
		total += 1;
	}
	countWrite += fwrite(buffer, sizeof(signed char), total , file);
}

void RleManager::GetNextBlock(int *buffer)
{
	short bufferShort = 0;
	signed char bufferChar;
	int count = 1;

	countRead += fread(&bufferShort, sizeof(short), 1, this->file);
	buffer[0] = bufferShort;
	while (count < 64)
	{
		countRead += fread(&bufferChar, sizeof(signed char), 1, this->file);
		if (bufferChar == 0)
		{
    		countRead += fread(&bufferChar, sizeof(signed char), 1, this->file);
			for (int i = 0; i < bufferChar; ++i)
			{
				buffer[count] = 0;
				count += 1;
			}
		}
		else
		{
			buffer[count] = bufferChar;
			count += 1;
		}
	}
	
}

void RleManager::GetNextBlockLuminance(int *buffer)
{
	short bufferShort = -1;
	int count = 1;

	countRead += fread(&bufferShort, sizeof(short), 1, this->file);

	buffer[0] = bufferShort;
	while (count < 64)
	{
		countRead += fread(&bufferShort, sizeof(short), 1, this->file);
	
		if (bufferShort == 0)
		{
    		countRead += fread(&bufferShort, sizeof(short), 1, this->file);
			for (int i = 0; i < bufferShort; ++i)
			{
				buffer[count] = 0;
				count += 1;
			}
		}
		else
		{
			buffer[count] = bufferShort;
			count += 1;
		}
	}
}

DCT_ENCODED *RleManager::RleDecode()
{
	int bufferRed[64];
	int bufferBlue[64];
	int bufferLum[64];
	short bufferShort;
	signed char bufferChar;

	DCT_ENCODED *DctTable = new DCT_ENCODED(header.height, header.width);

	int size = (header.height * header.width) / 4;
	int nbBlock = size / 64;
	int widthBlock = header.width / 8;
	int heightBlock = header.height / 8;

	for (int i = 0 ; i < heightBlock /2; ++i)
	{
		for (int j = 0 ; j < widthBlock /2; ++j)
		{
			//Blue
			GetNextBlock(bufferBlue);
			//Red
			GetNextBlock(bufferRed);

			for(int z = 0; z < 64; ++z)
			{
				int h = i * 8 + z / 8;
				int w = j * 8 + z % 8;
				DctTable->tabChrominance[h][w] = cv::Vec2i(bufferBlue[z], bufferRed[z]);
			}
		}
	}

	for (int count = 0; count < nbBlock * 4; ++count)
	{
		//Luminance
		GetNextBlockLuminance(bufferLum);
		for(int i = 0; i  < 64; ++i)
		{
			DctTable->luminance[i + (count * 64)] = bufferLum[i];
		}
	}
	return DctTable;
}